<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Title</title>
</head>
<body>
<h1>001-var/let/const区别</h1>
<button id="v001_b001">var/let/const作用域</button>
<script>
  {
    var var_scope = "var";
    let let_scope = "let"
    const const_scope = "const";
  }
  document.getElementById("v001_b001").addEventListener('click', function () {
    // 输出var
    console.log(var_scope);
    // 报错
    // console.log(let_scope);
    // 报错
    // console.log(const_scope);
  })
</script>
<br>
<span>var的for引起的问题(if也有)</span>
<button class="v001_c001">按钮1</button>
<button class="v001_c001">按钮2</button>
<button class="v001_c001">按钮3</button>
<button class="v001_c001">按钮4</button>
<button class="v001_c001">按钮5</button>
<script>
  // 无论点击哪个按钮，都是显示第5个(实际应该是0-4)
  var v001_c001 = document.getElementsByClassName("v001_c001");
  for (var i = 0; i < v001_c001.length; i++) {
    v001_c001[i].addEventListener('click', function () {
      console.log('第' + i + '个按钮被点击了');
    })
  }
</script>
<br>
<span>var的for引起的问题，可以使用闭包解决</span>
<button class="v001_c002">按钮1</button>
<button class="v001_c002">按钮2</button>
<button class="v001_c002">按钮3</button>
<button class="v001_c002">按钮4</button>
<button class="v001_c002">按钮5</button>
<script>
  // 因为函数是一个作用域，所以不会出现var的问题
  var v001_c002 = document.getElementsByClassName("v001_c002");
  for (var i = 0; i < v001_c001.length; i++) {
    (function (num) {
      v001_c002[num].addEventListener('click', function () {
        console.log('第' + num + '个按钮被点击了');
      });
    })(i);
  }
</script>
<br>
<span>换成let/const后不再出现var的问题</span>
<button class="v001_c003">按钮1</button>
<button class="v001_c003">按钮2</button>
<button class="v001_c003">按钮3</button>
<button class="v001_c003">按钮4</button>
<button class="v001_c003">按钮5</button>
<script>
  const v001_c003 = document.getElementsByClassName("v001_c003");
  for (let i = 0; i < v001_c003.length; i++) {
    v001_c003[i].addEventListener('click', function () {
      console.log('第' + i + '个按钮被点击了');
    })
  }
</script>
<h1>002-let/const区别</h1>
<button id="v002_b001">let变量可以赋值，const常量不可再次赋值</button>
<script>
  document.getElementById("v002_b001").addEventListener('click', function () {
    let letNum = 123;
    console.log(letNum);
    const constNum = 456;
    letNum = 111;
    // 报错
    // constNum = 222;
    console.log(letNum);
    console.log(constNum);
  })
</script>
<br>
<button id="v002_b002">常量对象的属性值是可以修改的</button>
<script>
  document.getElementById("v002_b002").addEventListener('click', function () {
    const obj = {
      name: 'ck',
      gender: 'men',
      year: 1998
    };
    console.log(obj);
    obj.name = 'yjm';
    obj.gender = 'women';
    obj.year = '1998';
    console.log(obj);
  })
</script>
<br>
<button id="v002_b003">对象字面量的普通写法和增强写法</button>
<script>
  document.getElementById("v002_b003").addEventListener('click', function () {
    const name = 'ck';
    const gender = 'men';
    const year = 1998;
    // 普通写法
    const obj = {
      name: name,
      gender: gender,
      year: year,
    }
    console.log(obj);
    // 增强写法
    const obj2 = {
      name,
      gender,
      year,
    }
    console.log(obj2);
  })
</script>
<br>
<button id="v002_b004">函数对象的普通写法和增强写法</button>
<script>
  document.getElementById("v002_b004").addEventListener('click', function () {
    // 普通写法
    const obj = {
      abc: function () {
        return {
          name: 'ck',
          gender: 'men',
          year: 1998
        }
      },
    }
    console.log(obj.abc());
    // 增强写法
    const obj2 = {
      abc() {
        return {
          name: 'ck',
          gender: 'men',
          year: 1998
        }
      },
    }
    console.log(obj2.abc());
  })
</script>
<h1>003-3种for循环遍历</h1>
<button id="v003_b001">普通for循环遍历</button>
<script>
  let str = ['a', 'b', 'c', 'd'];
  document.getElementById("v003_b001").addEventListener('click', function () {
    for (let i = 0; i < str.length; i++) {
      console.log(str[i]);
    }
  })
</script>
<br>
<button id="v003_b002">for-in遍历，取出下标</button>
<script>
  document.getElementById("v003_b002").addEventListener('click', function () {
    for (let index in str) {
      console.log(str[index]);
    }
  })
</script>
<br>
<button id="v003_b003">for-of遍历，取出对象</button>
<script>
  document.getElementById("v003_b003").addEventListener('click', function () {
    for (let item of str) {
      console.log(item);
    }
  })
</script>
<h1>004-高级函数filter/map/reduce</h1>
<h3>需求：找出小于50的数字、数值x2、相加</h3>
<button id="v004_b001">普通写法</button>
<script>
  let num = [12, 88, 23, 45, 76, 87, 40, 8];
  document.getElementById("v004_b001").addEventListener('click', function () {
    console.log(num);
    let num2 = [];
    for (let item of num) {
      if (item < 50) {
        num2.push(item);
      }
    }
    console.log(num2);
    let num3 = [];
    for (let item of num2) {
      num3.push(item * 2);
    }
    console.log(num3);
    let total = 0;
    for (let item of num3) {
      total += item;
    }
    console.log(total);
  })
</script>
<br>
<button id="v004_b002">高级写法</button>
<script>
  document.getElementById("v004_b002").addEventListener('click', function () {
    console.log(num);
    /*filter函数*/
    // 传入一个函数，函数内写执行逻辑，返回boolean，为true时添加到数组里面
    // 返回数组
    let num2 = num.filter(function (n) {
      return n < 50;
    });
    console.log(num2);
    /*map函数*/
    // 传入一个函数，返回的值添加到数组里面
    // 返回数组
    let num3 = num2.map(function (n) {
      return n * 2;
    });
    console.log(num3);
    /*reduce函数*/
    // 传入一个函数和初始值(不写默认为0)，函数第一个参数是前一个值，第二个是遍历的第n个对象
    // 返回数值
    let total = num3.reduce(function (preValue, n) {
      return preValue + n;
    }, 0);
    console.log(total);
  })
</script>
<br>
<button id="v004_b003">高级写法一起使用</button>
<script>
  document.getElementById("v004_b003").addEventListener('click', function () {
    let total = num.filter(function (n) {
      return n < 50;
    }).map(function (n) {
      return n * 2;
    }).reduce(function (preValue, n) {
      return preValue + n;
    }, 0);
    console.log(total);
  })
</script>
<h1>005-箭头表达式</h1>
<button id="v005_b001">高级写法使用箭头表达式</button>
<script>
  document.getElementById("v005_b001").addEventListener('click', function () {
    // 左侧是函数传入的值，右侧是函数返回的值
    // 传入多个参数需要写()
    let total = num.filter(n => n < 50).map(n => n * 2).reduce((preValue, n) => preValue + n, 0);
    console.log(total);
  })
</script>
<h3>箭头函数拓展：箭头函数主要用在：传入参数是函数时</h3>
<button id="v005_b002">原始函数写法</button>
<script>
  document.getElementById("v005_b002").addEventListener('click', function () {
    const a1 = function () {
      return 'a1';
    }
    console.log(a1());
  })
</script>
<br>
<button id="v005_b003">箭头函数无参写法</button>
<script>
  document.getElementById("v005_b003").addEventListener('click', function () {
    const a2 = () => {
      return 'a2';
    }
    console.log(a2());
  })
</script>
<br>
<button id="v005_b004">只有1个参数，可以省略括号</button>
<script>
  document.getElementById("v005_b004").addEventListener('click', function () {
    const a3 = n => {
      return n / 2;
    }
    console.log(a3(88));
  })
</script>
<br>
<button id="v005_b005">多个参数</button>
<script>
  document.getElementById("v005_b005").addEventListener('click', function () {
    const a4 = (m, n) => {
      return m + n;
    }
    console.log(a4(3, 6));
  })
</script>
<br>
<button id="v005_b006">只有1行代码，可以省略return和大括号</button>
<script>
  document.getElementById("v005_b006").addEventListener('click', function () {
    const a5 = (m, n) => m * n;
    console.log(a5(5, 7));
  })
</script>
<br>
<button id="v005_b007">特殊：只有1个参数，1行代码</button>
<script>
  document.getElementById("v005_b007").addEventListener('click', function () {
    const a6 = n => n * n;
    console.log(a6(9));
  })
</script>
<br>
<button id="v005_b008">箭头函数中this的指向</button>
<script>
  document.getElementById("v005_b008").addEventListener('click', function () {
    // this是由内向外查找，直到找到this停止
    // function ()是由Window回调的，所以是Window
    // () =>不是回调，setTimeout中没有this，a()中有this是obj
    const obj = {
      a() {
        // this
        console.log(this);  //obj

        // function
        setTimeout(function () {
          console.log(this);  //Window
        })
        // =>
        setTimeout(() => {
          console.log(this);  //obj
        })

        // function+function
        setTimeout(function () {
          setTimeout(function () {
            console.log(this);  //Window
          })
        })
        // =>+function
        setTimeout(function () {
          setTimeout(() => {
            console.log(this);  //Window
          })
        })
        // function+=>
        setTimeout(() => {
          setTimeout(function () {
            console.log(this);  //Window
          })
        })
        // =>+=>
        setTimeout(() => {
          setTimeout(() => {
            console.log(this);  //obj
          })
        })
      }
    }
    obj.a();
  })
</script>
<h1>006-prototype原型</h1>
<button id="v006_b001">prototype原型</button>
<script>
  document.getElementById("v006_b001").addEventListener('click', function () {
    // Object.prototype可以向所有变量加上一个属性
    const aaa = {
      name: 'a'
    }
    console.log(aaa);
    Object.prototype.aaa = aaa;
    const bbb = 'b';
    console.log(bbb);
    console.log(bbb.aaa);
  })
</script>
<h1>007-Promise的基本使用</h1>
<h3>如果要发送多个嵌套异步请求(比如ajax)(使用setTimeout代替ajax)，不进行管理代码逻辑会非常乱</h3>
<button id="v007_b001">默认方式</button>
<script>
  document.getElementById("v007_b001").addEventListener('click', function () {
    // 第一层
    setTimeout(() => {
      console.log('1默认方式');
      // 第二层
      setTimeout(() => {
        console.log('2默认方式');
        // 第三层
        setTimeout(() => {
          console.log('3默认方式');
        }, 1000)
      }, 1000)
    }, 1000)
  })
</script>
<br>
<button id="v007_b002">使用Promise进行管理(异步)</button>
<script>
  document.getElementById("v007_b002").addEventListener('click', function () {
    // Promise是一个对象，接收2个参数
    // resolve(解决)和reject(拒绝)(可选)是函数，可以表示是否符合条件
    // 如果是resolve则进行then(然后)，是reject进行catch(捕获)
    // 第一层
    new Promise((resolve, reject) => {
      // 这里写ajax请求，不要写业务代码
      // 一般成功调用resolve，失败调用reject
      // 第一层请求
      setTimeout(() => {
        // 可以传递数据
        resolve('1PromiseOk')
        // reject('1PromiseErr')
      }, 1000)
    }).then(data => {
      // 第一层成功
      // 如果调用了resolve会执行then
      // then接收函数参数，把成功的业务代码写这里
      console.log(data);
      // 第二层
      return new Promise((resolve, reject) => {
        // 第二层请求
        setTimeout(() => {
          // 如果某一层调用了reject方法，则后面的不会执行
          // reject('2PromiseErr')
          resolve('2PromiseOk')
        }, 1000)
      })
    }).then(data => {
          // 第二层成功
          console.log(data);
          // 第三层
          return new Promise((resolve, reject) => {
            // 第三层请求
            setTimeout(() => {
              // resolve('3PromiseOk')
              reject('3PromiseErr')
            }, 1000)
          })
        }
        // then还可以传递2个参数，第一个是resolve，第二个是reject
        // 如果此处被捕获到，后面的then还会继续执行，最下面的catch不会捕获到
        // , err => {
        //   console.log('then.err:' + err);
        // }
    ).then(data => {
          // 第三层成功
          console.log(data);
        }
    ).catch(err => {
      // 如果调用了reject会执行catch
      // catch接收函数参数，把失败业务代码写这里
      console.log(err);
    })
  })
</script>
<br>
<button id="v007_b003">使用Promise进行管理(非异步)</button>
<script>
  document.getElementById("v007_b003").addEventListener('click', function () {
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('非异步1PromiseOk')
      }, 1000)
    }).then(data => {
      console.log(data);
      // 不进行异步请求时，可以直接返回Promise.resolve或Promise.reject
      return Promise.resolve('非异步2PromiseOk')
      // return Promise.reject('非异步2PromiseErr')
    }).then(data => {
      console.log(data);
      // 还可以把Promise.resolve和Promise.reject简写为return和throw
      // return '非异步3PromiseOk'
      throw '非异步3PromiseErr'
    }).then(data => {
      console.log(data);
    }).catch(err => {
      console.log(err);
    })
  })
</script>
<br>
<button id="v007_b004">使用普通方法进行多请求处理(比较麻烦)</button>
<script>
  document.getElementById("v007_b004").addEventListener('click', function () {
    // 保存请求是否返回结果
    let isR1 = false
    let isR2 = false
    // 请求1
    setTimeout(() => {
      console.log('1多请求');
      isR1 = true
      handleR()
    }, 1000)
    // 请求2
    setTimeout(() => {
      console.log('2多请求');
      isR2 = true
      handleR()
    }, 1000)

    // 请求处理
    function handleR() {
      if (isR1 && isR2) {
        console.log('handleR');
      }
    }
  })
</script>
<br>
<button id="v007_b005">使用Promise进行管理(多请求)</button>
<script>
  document.getElementById("v007_b005").addEventListener('click', function () {
    // 传入一个数组，数组里是Promise对象
    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('1Promise多请求');
          resolve('Promise.all.Ok1')
          // reject('Promise.all.Err1')
        }, 1000)
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('2Promise多请求');
          resolve('Promise.all.Ok2')
          // reject('Promise.all.Err2')
        }, 1000)
      })
    ]).then(results => {
      // 接收一个结果集
      console.log(results);
    }).catch(err => {
      // 捕获异常
      console.log(err);
    })
  })
</script>
<h1>008-数组、对象的解构</h1>
<button id="v008_b001">数组解构</button>
<script>
  document.getElementById("v008_b001").addEventListener('click', function () {
    function f1() {
      return [1, 2, 3];
    }

    let [a, b, c] = f1();
    console.log(a, b, c); // 1  2  3
    let [d, , f] = f1();
    console.log(d, f); // 1  3
    let [e,] = f1();
    console.log(e); // 1
  })
</script>
<br>
<button id="v008_b002">对象解构</button>
<script>
  document.getElementById("v008_b002").addEventListener('click', function () {
    function f2() {
      return {
        a: '1',
        b: '2',
        c: '3'
      };
    }

    // 原变量名:新变量名
    let {a: x, b: y, c: z} = f2();
    console.log(x, y, z); // 1  2  3
    // 简写
    let {a, b, c} = f2();
    console.log(a, b, c); // 1  2  3
  })
</script>
<h1>008-数组的特殊用法</h1>
<button id="v009_b001">数组的特殊用法</button>
<script>
  document.getElementById("v009_b001").addEventListener('click', function () {
    let a = [1, 2, 3];
    let b = [4, 5, 6];
    // 需求：把b插入到a后
    // 做法1：使用for循环
    for (i of b) {
      a.push(i);
    }
    console.log(a);
    // 做法2：使用...语法，push可以接受多个值
    a.push(...b);
    console.log(a);
    // 例如a.push(9,8,7);是把9,8,7插入到a后
    a.push(9, 8, 7);
    console.log(a);
  })
</script>
</body>
</html>
